import Glibc
//import Darwin
class Timer {
    private let CLOCK_REALTIME = 0
    private var start_timespec = timespec()
    private var end_timespec = timespec()
    private var time_spec = timespec()
    func start() {
        clock_gettime(Int32(CLOCK_REALTIME),&start_timespec)
    }
    
    func stop() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&end_timespec)
        let start_time = Double(start_timespec.tv_sec * 1_000_000 + start_timespec.tv_nsec / 1_000)
        let end_time = Double(end_timespec.tv_sec * 1_000_000 + end_timespec.tv_nsec / 1_000)
        let time = end_time - start_time
        return time / 1_000
    }
    func getTime() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&time_spec)
        return Double(time_spec.tv_sec * 1_000_000 + time_spec.tv_nsec / 1_000)
    }
}

let timer = Timer()

func approximate(_ n: Int) -> Double {
    var u = Array(repeating: 1.0, count: n)
    
    var v = Array(repeating: 0.0, count: n)
    for _ in 1...10 {
        multiplyAtAv(n,u,&v)
        multiplyAtAv(n,v,&u)
    }
    
    var vBv = 0.0, vv = 0.0
    for i in 0..<n {
        vBv += u[i]*v[i]
        vv  += v[i]*v[i]
    }
    
    return sqrt(vBv/vv)
}

func a(_ i: Int, _ j: Int) -> Double {
    let ij = i+j
    return 1.0 / Double( ij*(ij+1)/2 + i+1 )
}

func multiplyAv(_ n: Int, _ v: [Double], _ av: inout [Double]) {
    for i in 0..<n {
        av[i] = 0.0;
        for j in 0..<n {
            av[i] += a(i,j)*v[j]
        }
    }
}

func multiplyAtv(_ n: Int, _ v: [Double], _ atv: inout [Double]) {
    for i in 0..<n {
        atv[i] = 0;
        for j in 0..<n {
            atv[i] += a(j,i)*v[j]
        }
    }
}

func multiplyAtAv(_ n: Int, _ v: [Double], _ atAv: inout [Double]) {
    var u = Array(repeating: 0.0, count: n)
    multiplyAv(n,v,&u)
    multiplyAtv(n,u,&atAv)
}

func runSpectralnorm()->Int{
    let n: Int = 5500;
    timer.start()
    _ = approximate(n)
    let time = timer.stop()
    // print("Benchmark - Swift - spectralnorm - " + String((end - begin)*1000) + " ms")
    return Int(time)
}

print("Spectralnorm:\t\(runSpectralnorm())\tms")